package com.lhf.dajiuye.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lhf.dajiuye.config.WxConfig;
import com.lhf.dajiuye.domain.LoginInfo;
import com.lhf.dajiuye.domain.User;
import com.lhf.dajiuye.service.RestService;
import com.lhf.dajiuye.service.UserService;
import com.lhf.dajiuye.service.WxService;
import com.lhf.dajiuye.utils.EncryptUtil;
import com.lhf.dajiuye.utils.WxPKCS7Encoder;
import com.lhf.dajiuye.utils.WxUtil;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 解密encryptedData，获取微信用户信息
 * 调用接口获取登录凭证（code）。通过凭证进而换取用户登录态信息，包括用户的唯一标识（openid）及本次登录的
 * 会话密钥（session_key）等。用户数据的加解密通讯需要依赖会话密钥完成。
 *
 * 通过wx.login获取登录凭证code  ，然后调用后台接口wx.request发送参数code调用接口换取openid和session_key,
 * wx.checkSession检测当前用户登录态是否有效
 */
@Service
@Slf4j
public class WxServiceImpl implements WxService {

    @Autowired
    WxConfig wxConfig;

    @Autowired
    RestService restService;

    @Autowired
    UserService userService;

    /**
     * 解密用户的数据
     * @param loginInfo
     * @return
     */
    @Override
    public Map getUserInfo(LoginInfo loginInfo) {
        String code = loginInfo.getCode();
        String encryptedData = loginInfo.getEncryptedData();
        String iv = loginInfo.getIv();
        Map tempMap = getSessionKeyOpenId(code);
        String sessionKey = (String)tempMap.get("session_key");
        String openId = (String)tempMap.get("openid");
        // 字符串数组
        String realMsg = doGetUserInfo2(encryptedData, sessionKey, iv);
        // realMsg才是真正要返回的数据
        Map resMap = WxUtil.strToMap(realMsg);
        resMap.put("myEncrypt", EncryptUtil.encryptUtil(openId));
        boolean tag = updateUser(openId, sessionKey, resMap);
        return resMap;
    }

    /**
     * 更新用户信息或者插入新用户;同时为map添加userId和resume
     * @return
     * @param openId
     * @param sessionKey
     * @param map
     */
    public boolean updateUser(String openId, String sessionKey, Map map){
        if(!StringUtils.hasLength(openId)){
            log.info("openId为null");
            return false;
        }
        User user = userService.getUserByOpenId(openId);
        String userId;
        String resume="";
        if(user!=null){
            userId=user.getId();
            resume=user.getResume();
            // 因为用户信息可能会变，及时更新
            user.setNickName((String) map.getOrDefault("nickName",""));
            user.setGender((Integer) map.getOrDefault("gender",0));
            user.setCity((String) map.getOrDefault("city",""));
            user.setProvince((String) map.getOrDefault("province",""));
            user.setAvatar((String) map.getOrDefault("avatarUrl",""));
            user.setSessionKey(sessionKey);

            int i = userService.updateUser(user);
            log.info("更新完用户返回值i="+i);
        }else {
            // 当前为新用户
            User newUser = new User();
            newUser.setOpenId(openId);
            newUser.setNickName((String) map.getOrDefault("nickName",""));
            newUser.setGender((Integer) map.getOrDefault("gender",0));
            newUser.setCity((String) map.getOrDefault("city",""));
            newUser.setProvince((String) map.getOrDefault("province",""));
            newUser.setAvatar((String) map.getOrDefault("avatarUrl",""));
            newUser.setSessionKey(sessionKey);
            userId = String.valueOf(userService.saveUser(newUser));
        }
        // jsonMap的数据添加用户id和简历，方便发送简历的时候获取
        map.put("id",userId);
        map.put("resume",resume);
        return true;
//        String sessionKey = (String)ret.get("session_key");
//            String openId=(String) ret.get("openid");

//            if(realMsg==null){
//                // 解析失败
//                System.out.println("===========msg为null,获取数据失败");
//                return "msg为null";
//            }
            // 存储解密后的用户数据的map
//            Map jsonMap = JSON.parseObject(realMsg, Map.class);

//            if(jsonMap.getOrDefault("watermark","null")!=null){
//                // watermark里面有appId,出于安全剔除它
//                jsonMap.remove("watermark");
//            }

//            if(StringUtils.hasLength(openId)){
//                // openId进行加密返回客户端
//                String encryptId = EncryptUtil.encryptUtil(openId);
//                jsonMap.put("myEncrypt",encryptId);
//            }

//            String id=null;
//            String nickName = (String)jsonMap.get("nickName");
//            int gender = (int)jsonMap.get("gender");
////        String language = (String)jsonMap.get("language");
//            String city = (String)jsonMap.get("city");
//            String province = (String)jsonMap.get("province");
////        String country = (String)jsonMap.get("country");
//            String avatarUrl = (String)jsonMap.get("avatarUrl");
////        Date lastLoginTime=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date());
//            Date lastLoginTime=new Date();
//
//            User user = userService.getUserByOpenId(openId);
//
//            log.info("查询到openId为{}的user是:{}===============",openId,user);
//
//            if(user!=null){
//                id = user.getId();
//                String resume = user.getResume();
//                String comId = user.getComId();
//                // jsonMap的数据添加用户id和简历，方便发送简历的时候获取
//                jsonMap.put("resume",resume);
//                jsonMap.put("comId",comId);
//
//                user.setSessionKey(sessionKey);
//                user.setNickName(nickName);
//                user.setGender(gender);
//                user.setCity(city);
//                user.setProvince(province);
//                user.setAvatar(avatarUrl);
//                int i = userService.updateUser(user);
//                System.out.println("com.lhf.dajiuye.aspect.PostSaveAspect.around：更新user后i=========="+i);
//            }else {
//                // 当前为新用户
//                User newUser = new User();
////                newUser.setId(id);
//                newUser.setOpenId(openId);
//                newUser.setSessionKey(sessionKey);
//                newUser.setNickName(nickName);
//                newUser.setGender(gender);
//                newUser.setCity(city);
//                newUser.setProvince(province);
//                newUser.setAvatar(avatarUrl);
//                id = String.valueOf(userService.saveUser(newUser));
//            }
//            // 添加id到返回结果中，方便前端获取id
//            jsonMap.put("id",id);
//            obj=jsonMap;
    }

    /**
     * 获取sessionKey 调用官方接口
     * https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
     * 注意这里如果对getSessionKey进行增强的话会失败，因为调用者的不是增强后的方法，而是增强前的方法
     */
    public Map getSessionKeyOpenId(String code){
        String protocol="https";
        String url = wxConfig.getUrl();
        String appid = wxConfig.getAppid();
        String secret = wxConfig.getSecret();
        String js_code=code;
        String grant_type = wxConfig.getGrantType();
        // 请求参数
        HashMap<String, String> jsonMap = new HashMap<>();
        jsonMap.put("appid",appid);
        jsonMap.put("secret",secret);
        jsonMap.put("js_code",js_code);
        jsonMap.put("grant_type",grant_type);

        // 调用http客户端服务向微信接口code2Session获取session_key和openId
        String json = restService.sendGet(protocol, url, jsonMap);
        //        log.info("body是============={}",body);
        HashMap map = JSON.parseObject(json, HashMap.class);
        return map;
//        log.info("session_key:=========={}",map.get("session_key"));
//        return (String) (map.getOrDefault("session_key","获取失败"));
    }

    /**
     * 真正处理解密，并返回解密后字符串
     * {"nickName":"moon","gender":0,"language":"zh_CN","city":"","province":"","country":"","avatarUrl":"https://thirdwx.qlogo.cn/mmopen/vi_32/IUekiUPtlw/132",
     * "watermark":{"timestamp":1635261332,"appid":"wx6ba09ab0d4dcc6e3"}}
     * @param encryptedData
     * @param sessionKey
     * @param iv
     * @return
     */
    public String doGetUserInfo2(String encryptedData, String sessionKey, String iv){
        try {

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

            BASE64Decoder base64Decoder = new BASE64Decoder();

            byte[] _encryptedData = base64Decoder.decodeBuffer(encryptedData);

            byte[] _sessionKey = base64Decoder.decodeBuffer(sessionKey);

            byte[] _iv = base64Decoder.decodeBuffer(iv);

            SecretKeySpec secretKeySpec = new SecretKeySpec(_sessionKey, "AES");

            IvParameterSpec ivParameterSpec = new IvParameterSpec(_iv);

            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

            byte[] original = cipher.doFinal(_encryptedData);

            byte[] bytes = WxPKCS7Encoder.decode(original);

            String originalString = new String(bytes, Charset.forName("utf-8"));

            return originalString;

        } catch (Exception ex) {

            return null;

        }
    }

    /**
     * 这种不知道为什么解密失败
     * @param encryptedData
     * @param sessionKey
     * @param iv
     * @return
     */
    @Deprecated
    public JSONObject doGetUserInfo(String encryptedData, String sessionKey, String iv){
        // 被加密的数据
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);

        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return JSONObject.parseObject(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
